package ac.svn.accesscontrol.controller;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import ac.notification.event.INotificationListener;
import ac.notification.event.NotificationEvent;
import ac.notification.manager.NotificationRegistrar;
import ac.svn.accesscontrol.manager.SVNInfoManager;
import ac.svn.accesscontrol.store.Dictionary;
import ac.svn.accesscontrol.store.GroupDetails;
import ac.svn.accesscontrol.store.ISVNIdentifier;
import ac.svn.accesscontrol.store.ISVNItem;
import ac.svn.accesscontrol.store.LocationDetails;
import ac.svn.accesscontrol.store.SVNGroup;
import ac.svn.accesscontrol.store.SVNLocation;
import ac.svn.accesscontrol.store.SVNUser;
import ac.svn.accesscontrol.store.UserDetails;
import ac.svn.accesscontrol.utils.Utility;

public class InformationAssembler implements INotificationListener,ISVNIdentifier {


    public InformationAssembler()
    {
	NotificationRegistrar.registerListener(this);
    }    


    //==================================================//
    //			OVERRIDDEN SECTION		//
    //==================================================//
    @Override
    public Set<String> declaredSubscriptionSet() {
	Set<String> subscriptions = new HashSet<String>();
	subscriptions.add(CMD_ASSEMBLE_INFORMATION);
	subscriptions.add(CMD_MERGE_INFORMATION);
	return subscriptions;
    }

    @Override
    public void receiveEvent(NotificationEvent ne)
    {
	final String neId = ne.getPropertyIdentifier();

	//Check if assembly command is called.
	if(neId.contains(CMD_ASSEMBLE_INFORMATION))
	{
	    assembleCommandHandler();
	}
	else if(neId.contains(CMD_MERGE_INFORMATION))
	{
	    //Get save after merge preference.
	    Boolean saveRequired = (Boolean) ne.getPropertyValue();

	    //If not present consider no saving.
	    if(null == saveRequired)
	    {	    
		mergeInformationHandler(false);
	    }
	    //If save preference is present save after merging.
	    else
	    {
		mergeInformationHandler(saveRequired.booleanValue());
	    }
	}

    }

    /**
     * Method is responsible for merging information present in SVNInformation Manager
     * with information present in dictionary.
     * */
    private void mergeInformationHandler(boolean saveRequired) 
    {
	Dictionary dictionary 		= Dictionary.getDictionary();	
	SVNInfoManager infoManager 	= SVNInfoManager.getInfoManager();

	//Merge information for users.
	for(ISVNItem userItem: infoManager.getAllUsers())
	{
	    SVNUser svnUser = (SVNUser) userItem;

	    //Get existing user details.
	    UserDetails userDetails = dictionary.getUserDetails(svnUser.getId());

	    //If such detail is present.
	    if(null != userDetails)
	    {
		userDetails.setUserName(svnUser.getUserName());
		userDetails.setLastUpdated(new Date());
	    }

	}


	//Merge Information for groups
	for(ISVNItem groupItem: infoManager.getAllGroups())
	{
	    SVNGroup svnGroup = (SVNGroup) groupItem;

	    //Get already existent details.
	    GroupDetails details = dictionary.getGroupDetails().get(svnGroup.getId());

	    //If details are present.
	    if(null == details)
	    {
		details = new GroupDetails(svnGroup.getGroupName(),svnGroup.getGroupAlias());
	    }
	    else
	    {
		details.setGroupName(svnGroup.getGroupName());
		details.setGroupAlias(svnGroup.getGroupAlias());
		details.setLastUpdated(new Date());
	    }

	    dictionary.getGroupDetails().put(svnGroup.getId(), details);
	}   


	//Merge Location Details.
	for(ISVNItem locationItem: infoManager.getAllLocations())
	{
	    SVNLocation location =(SVNLocation) locationItem;

	    //Get already existing details.
	    LocationDetails locationDetails = dictionary.getLocationDetails().get(location.getId());

	    //If details are present.
	    if(null == locationDetails)
	    {
		locationDetails = new LocationDetails(location.getLocationName(),location.getLocationPath());
	    }
	    else
	    {
		locationDetails.setLocationName(location.getLocationName());
		locationDetails.setLocationURL(location.getLocationPath());
		locationDetails.setLastUpdated(new Date());
	    }

	    dictionary.getLocationDetails().put(location.getId(), locationDetails);	    
	}

	//If Saving is required send notification to respective module.
	Utility.sendNotification(N_CONFIG_MERGED);
	
	if(saveRequired)
	{
	    //Send notification that configuration has been loaded.
	    Utility.sendNotification(CMD_SAVE_CONFIG);
	}

    }


    /**
     * Method assembles information read from access file and Information saved.
     */
    private void assembleCommandHandler() 
    {
	Dictionary dictionary 		= Dictionary.getDictionary();	
	SVNInfoManager infoManager 	= SVNInfoManager.getInfoManager();
	//Get Additional information for Users of the SVN.
	for(ISVNItem userItem : infoManager.getAllUsers())
	{
	    SVNUser user = (SVNUser) userItem;
	    UserDetails userDetails = dictionary.getUserDetails(userItem.getId());

	    //Check if any details are present for current user.
	    if(null != userDetails)
	    {
		user.setUserName(userDetails.getUserName());
	    }
	    infoManager.updateUser(user);
	}


	//Get additional information for Groups in the SVN.
	for(ISVNItem groupItem : infoManager.getAllGroups())
	{
	    SVNGroup svnGroup 		= (SVNGroup) groupItem;
	    GroupDetails groupDetails 	= dictionary.getGroupDetails().get(svnGroup.getId());	 

	    //Check if any details are present for current group.
	    if(null != groupDetails)
	    {
		svnGroup.setGroupName(groupDetails.getGroupName());
	    }
	    infoManager.updateGroup(svnGroup);
	}


	//Get Additional information saved for Locations.
	for(ISVNItem locationItem : infoManager.getAllLocations())
	{
	    SVNLocation location 		= (SVNLocation) locationItem;
	    LocationDetails locationDetails	= dictionary.getLocationDetails().get(locationItem.getId());

	    if(null != locationDetails)
	    {
		location.setLocationName(locationDetails.getLocationName());
	    }

	    infoManager.updateLocation(location);
	}

	//Send notification that configuration has been loaded.
	Utility.sendNotification(N_CONFIG_LOADED);

	//Once Information is updated, Send notification for UI Updates. 
	Utility.sendNotification(N_UPDATE_INFORMATION);
    }

}
